﻿using System.Collections.Generic;
using System.Globalization;
using System.Linq;

namespace Ewk.Math.Numerics.PositionalNumeralSystems
{
    /// <summary>
    /// Represents the decimal number system.
    /// </summary>
    public class Decimal : IPositionalNumber
    {
        private IList<int> _numbers;

        /// <summary>
        /// Initializes a new instance.
        /// </summary>
        /// <param name="value">The value of the decimal.</param>
        public Decimal(long value)
        {
            DecimalValue = value;
        }

        #region Implementation of IPositionalNumber

        public IList<int> Numbers
        {
            get { return _numbers ?? (_numbers = ComputeNumbers(DecimalValue)); }
        }

        public long DecimalValue { get; private set; }

        #endregion

        public override string ToString()
        {
            return DecimalValue.ToString(CultureInfo.InvariantCulture);
        }

        #region Overloaded operators

        /// <summary>
        /// Implicitly creates a <see cref="Complex"/> from a <see cref="int"/>.
        /// </summary>
        public static implicit operator Decimal(Factorial value)
        {
            var decimalValue = value.Numbers
                                    .Select((x, i) =>
                                            Factorial(i + 1)*x)
                                    .Sum();

            return new Decimal(decimalValue);
        }

        #endregion

        static IList<int> ComputeNumbers(long decimalValue)
        {
            var list = new List<int>();

            while (decimalValue > 0)
            {
                var i = 0;
                double power = 1;
                while (power <= decimalValue)
                {
                    i++;
                    power *= 10;
                }

                while (i > list.Count)
                {
                    list.Add(0);
                }

                power = System.Math.Pow(10, i - 1);
                var factor = System.Math.Floor(decimalValue / power);
                list[i - 1] = (int)factor;

                decimalValue -= (long)(factor * power);
            }

            return list;
        }

        static long Factorial(int factor)
        {
            long factorial = 1;

            for (var i = 1; i <= factor; i++)
            {
                factorial *= i;
            }

            return factorial;
        }
    }
}